package eventRegistration

import (
	"end/config"
	"end/entry"
	"end/httpEntry"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"math"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"
)

type EventDto struct {
	ID         int            `json:"id" gorm:"column:id"`
	UserID     int            `json:"userid" gorm:"column:userid"`
	ActivityID int            `json:"activityid" gorm:"column:activityid"`
	Status     int            `json:"status" gorm:"column:status"`
	CreateTime time.Time      `json:"createtime" gorm:"column:createtime"`
	Imgs       string         `json:"imgs" gorm:"column:imgs"`
	UpdateTime time.Time      `json:"updatetime" gorm:"column:updatetime"`
	Starttime  time.Time      `json:"starttime" gorm:"column:starttime"`
	Endtime    time.Time      `json:"endtime" gorm:"column:endtime"`
	Work       float64        `json:"work" gorm:"column:work"`
	Activity   entry.Activity `json:"activity" gorm:"foreignkey:ActivityID"`
}

var lock sync.Mutex

type EventDtoUser struct {
	ID         int            `json:"id" gorm:"column:id"`
	UserID     int            `json:"userid" gorm:"column:userid"`
	ActivityID int            `json:"activityid" gorm:"column:activityid"`
	Status     int            `json:"status" gorm:"column:status"`
	CreateTime time.Time      `json:"createtime" gorm:"column:createtime"`
	Imgs       string         `json:"imgs" gorm:"column:imgs"`
	UpdateTime time.Time      `json:"updatetime" gorm:"column:updatetime"`
	Starttime  time.Time      `json:"starttime" gorm:"column:starttime"`
	Endtime    time.Time      `json:"endtime" gorm:"column:endtime"`
	Work       float64        `json:"work" gorm:"column:work"`
	User       entry.User     `json:"user" gorm:"foreignkey:UserID"`
	Activity   entry.Activity `json:"activity" gorm:"foreignkey:ActivityID"`
}

func (EventDto) TableName() string {
	return "eventregistration"
}

func (EventDtoUser) TableName() string {
	return "eventregistration"
}

type EventAllRequest struct {
	Activityid int `json:"activityid" binding:"required"`
}

func EventAll(r *gin.Engine) {
	// 报名
	r.POST("/event/registration", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		var eventAllRequest EventAllRequest
		err := context.ShouldBind(&eventAllRequest)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		// 检测自己是否报名了这个活动
		var eventRegistration entry.Eventregistration
		db := config.GetDb()
		result := db.Where("userid = ? and activityid = ?", userinfo.Id, eventAllRequest.Activityid).First(&eventRegistration)
		// 报名了没有错误
		if result.Error == nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10024,
				Error: httpEntry.ERROR10024,
			})
			return
		}
		// 活动是否存在
		var activity entry.Activity
		result = db.Where("id = ?", eventAllRequest.Activityid).First(&activity)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		// 检测人数是否已经满了
		lock.Lock()
		defer lock.Unlock()
		if activity.AlreadyNum == activity.Num {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10028,
				Error: httpEntry.ERROR10028,
			})
			return
		}
		// 检测超时
		currentTime := time.Now()
		if !(currentTime.After(activity.RegistrationStarttime) && currentTime.Before(activity.RegistrationDeadline)) {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10025,
				Error: httpEntry.ERROR10025,
			})
			return
		}
		activity.AlreadyNum += 1
		db.Updates(activity)
		// 释放锁
		eventRegistration = entry.Eventregistration{
			CreateTime: time.Now(),
			UserID:     userinfo.Id,
			ActivityID: eventAllRequest.Activityid,
			Status:     httpEntry.STATUS1,
			UpdateTime: time.Now(),
			AdminId:    activity.AdminID,
			Work:       0,
		}
		db.Create(&eventRegistration)
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"data":    eventRegistration,
			"message": "报名成功",
		})
	})

	type AdminEventAllRequest struct {
		Status     int `json:"status" binding:"required"`
		Page       int `json:"page" binding:"required"`
		Activityid int `json:"activityid" binding:"required"`
	}

	type EventStarttime struct {
		ActivityId string `json:"activityId" binding:"required"`
	}

	// 扫码进行判断
	r.POST("/event/scan", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		var eventStarttime EventStarttime
		err := context.ShouldBind(&eventStarttime)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		activityid, err := config.Decrypt(eventStarttime.ActivityId)
		split := strings.Split(activityid, "|")
		oldTime, err := strconv.ParseInt(split[2], 10, 64)
		// 不可以超过一个小时
		if time.Now().Unix()-oldTime > 60*30 {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}

		activityid = split[0]
		num := 0
		// 0表示开始，1表示结束
		if split[1] == "0" {
			num = 0
		} else {
			num = 1
		}
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		var event EventDto
		tx := db.Preload("Activity").Where("userid = ? and activityid = ?", userinfo.Id, activityid).First(&event)
		if tx.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		if num == 1 {
			event.Starttime = time.Now()
		} else {
			if event.Starttime.IsZero() {
				context.JSON(http.StatusOK, httpEntry.BaseResponse{
					Code:  10014,
					Error: "开始二维码没有扫描",
				})
				return
			}
			if event.Starttime.Before(event.Activity.StartTime) {
				event.Starttime = event.Activity.StartTime
			}
			if event.Endtime.After(event.Activity.EndTime) {
				event.Endtime = event.Activity.EndTime
			}
			event.Endtime = time.Now()
			minutes := event.Endtime.Sub(event.Starttime).Minutes()
			// 增加工作时间
			event.Work += minutes / 60
			// 改成0
			event.Starttime = time.Time{}
		}
		db.Model(&entry.Eventregistration{}).Where("id = ?", event.ID).Updates(map[string]interface{}{
			"work":      math.Round(event.Work*100) / 100,
			"endtime":   event.Endtime,
			"starttime": event.Starttime,
		})
		context.JSON(http.StatusOK, httpEntry.BaseResponse{
			Code:    200,
			Message: "成功",
		})
	})

	// 管理员每一个不同活动的报名情况
	r.POST("/admin/event/all", httpEntry.LoginMiddleware(), httpEntry.AdminMiddleware(), func(context *gin.Context) {
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		// 遍历
		var adminEventAllRequest AdminEventAllRequest
		err := context.ShouldBind(&adminEventAllRequest)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		if adminEventAllRequest.Page == 0 {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		db := config.GetDb()
		var dtos []EventDtoUser
		result := db.Preload("User").Preload("Activity").
			Where("status = ? and adminid = ? and activityid = ?",
				adminEventAllRequest.Status, userinfo.Id, adminEventAllRequest.Activityid).
			Offset((adminEventAllRequest.Page - 1) * 20).Limit(20).Order("starttime").Find(&dtos)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		for i := range dtos {
			dtos[i].User.Password = ""
			dtos[i].User.OpenID = ""
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "请求成功",
			"data":    dtos,
		})
	})

	type UserEventAllRequest struct {
		Status int `json:"status" binding:"required"`
		Page   int `json:"page" binding:"required"`
	}

	// 用户全部报名成功的活动
	r.POST("/user/event", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		// 遍历
		var userEventAllRequest UserEventAllRequest
		err := context.ShouldBind(&userEventAllRequest)
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		db := config.GetDb()
		var dtos []EventDto

		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		if userEventAllRequest.Status&config.STATUS6 != 0 {
			now := time.Now()
			db.Preload("Activity").
				Joins("join activity on activity.endtime < ? AND activity.id = eventregistration.activityid", now). // 连接 activity 表
				Where("eventregistration.status & ?", httpEntry.STATUS1).
				Offset((userEventAllRequest.Page - 1) * 20).
				Limit(20).Find(&dtos)
		} else {
			db.Preload("Activity").Where("userid = ? and status & ?", userinfo.Id, userEventAllRequest.Status).
				Offset((userEventAllRequest.Page - 1) * 20).
				Limit(20).Find(&dtos)
		}
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "获取成功",
			"data":    dtos,
		})
	})

	type EventUpdateRequest struct {
		Eventid int    `json:"eventid" binding:"required"`
		Imgs    string `json:"imgs"`
	}

	// 照片上传
	r.POST("/event/update", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		var eventUpdateRequest EventUpdateRequest
		err := context.ShouldBind(&eventUpdateRequest)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}
		var event EventDto
		db := config.GetDb()
		result := db.Preload("Activity").Where("id = ?", eventUpdateRequest.Eventid).First(&event)
		now := time.Now()
		if event.Activity.StartTime.After(now) || event.Activity.EndTime.Before(now) {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10031,
				Error: httpEntry.ERROR10031,
			})
			return
		}
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		if event.UserID != userinfo.Id {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10011,
				Error: httpEntry.ERROR10011,
			})
			return
		}
		// 判断是否在活动期间
		currentTime := time.Now()
		if !(currentTime.After(event.Activity.StartTime) && currentTime.Before(event.Activity.EndTime)) {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10031,
				Error: httpEntry.ERROR10031,
			})
			return
		}
		db.Model(&entry.Eventregistration{}).Where("id = ?", event.ID).Updates(map[string]interface{}{
			"imgs": eventUpdateRequest.Imgs,
		})
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "上传成功",
		})
	})

	type EventAuditRequest struct {
		Eventid int `json:"eventid" binding:"required"`
		Status  int `json:"status" binding:"required"`
	}

	r.GET("/event/info/:id", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		id := context.Param("id")
		if id == "" || id == "0" {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10029,
				Error: httpEntry.ERROR10029,
			})
			return
		}
		var event entry.Eventregistration
		db := config.GetDb()
		db.Where("id = ?", id).First(&event)
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "获取成功",
			"data":    event,
		})
	})

	// 活动审核，审核成功用户获取积分
	r.POST("/event/audit", httpEntry.LoginMiddleware(), httpEntry.AdminMiddleware(), func(context *gin.Context) {
		var eventAuditRequest EventAuditRequest
		err := context.ShouldBind(&eventAuditRequest)
		if err != nil || eventAuditRequest.Eventid == 0 {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10006,
				Error: httpEntry.ERROR10006,
			})
			return
		}

		userinfo := context.MustGet("userinfo").(config.UserInfo)
		var event EventDto
		db := config.GetDb()
		result := db.Preload("Activity").Where("id = ? and starttime is not null and endtime is not null",
			eventAuditRequest.Eventid).First(&event)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10005,
				Error: httpEntry.ERROR10005,
			})
			return
		}
		// 判断这个活动是不是管理员的
		if event.Activity.AdminID != userinfo.Id {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10011,
				Error: httpEntry.ERROR10011,
			})
			return
		}
		// 更新状态
		db.Model(&entry.Eventregistration{}).Where("id = ?", event.ID).Update("status", eventAuditRequest.Status)
		// 不增加积分
		if eventAuditRequest.Status&httpEntry.STATUS2 == 0 {
			// 用户积分更新
			context.JSON(http.StatusOK, gin.H{
				"code":    200,
				"message": "操作成功",
			})
			return
		}
		// 增加积分，先查询用户
		var user entry.User
		result = db.Where("id = ?", event.UserID).First(&user)
		if result.Error != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10014,
				Error: httpEntry.ERROR10014,
			})
			return
		}
		// 积分计算
		// 如果是小时计算
		if event.Activity.Type == "0" {
			user.Integral += int(event.Work * 5)
		} else {
			user.Integral += event.Activity.Integral
		}
		// 如果是直接计算
		db.Updates(user)
		// 用户积分更新
		context.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "操作成功",
		})
	})

	r.GET("/event/del/:id", httpEntry.LoginMiddleware(), func(context *gin.Context) {
		evenidStr := context.Param("id")
		evenid, err := strconv.Atoi(evenidStr)
		if err != nil {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10029,
				Error: httpEntry.ERROR10029,
			})
			return
		}
		userinfo := context.MustGet("userinfo").(config.UserInfo)
		db := config.GetDb()
		var event entry.Eventregistration
		db.Where("id = ?", evenid).First(&event)
		if event.UserID != userinfo.Id {
			context.JSON(http.StatusOK, httpEntry.BaseResponse{
				Code:  10011,
				Error: httpEntry.ERROR10011,
			})
			return
		}
		db.Delete(event)
		db.Model(entry.Activity{}).Where("id = ?", event.ActivityID).Updates(map[string]interface{}{
			"already_num": gorm.Expr("already_num - ?", 1),
		})
		context.JSON(http.StatusOK, httpEntry.BaseResponse{
			Code:    200,
			Message: "操作成功",
		})
	})
}
